/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server;

import java.net.*;
import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Date;
import model.*;

/**
 *
 * @author Солнце
 */
public class Server {

    public static int id = 0;
    public static Flights all = new Flights();
    private static List<Thread> allClients = new LinkedList<Thread>();

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        System.out.println("Запускаем сервер...");
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(12371);
            System.out.println("Сервер запущен!");
            //all = (Flights) loadDataFromServer("flightsServ.xml", Flights.class);
            all = (Flights) ProcessXMLData.loadDataFromXML(ProcessXMLData.saveDataToXML(ProcessXMLData.loadData("FlightsServ.xml", Flights.class)), Flights.class);
        } catch (IOException e) {
            System.out.println("Порт 12371 занят.");
            System.exit(-1);
        }

        try {
            while (true) {
                Socket clientSocket;
                try {
                    clientSocket = serverSocket.accept();
                    Thread read = new IOThread(clientSocket);
                    read.start();
                    allClients.add(read);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        } finally {
            serverSocket.close();
        }
    }

    private static class IOThread extends Thread implements InterfaceObserver {

        private Socket clientSocket = null;

        public IOThread(Socket socket) {
            clientSocket = socket;
        }

        @Override
        /**
         * Метод, обрабатывающий запрос клиента
         */
        public void run() {
            //Подготовка
            ObjectInputStream sIn = null;
            ObjectOutputStream sOut = null;
            String command;
            String data;
            String filename;
            String client;

            try {
                //GZIPInputStream gsIn = new GZIPInputStream(clientSocket.getInputStream());
                BufferedInputStream bIn = new BufferedInputStream(clientSocket.getInputStream());
                //sIn = new ObjectInputStream(gsIn);
                sIn = new ObjectInputStream(bIn);
                try {
                    //Ждём имя клиента: Object -> String
                    client = (String) sIn.readObject();
                    System.out.println("Клиент: " + client);
                    //Ждём команду: Object -> String
                    command = (String) sIn.readObject();
                    System.out.println("Команда: " + command);
                    //Поиск
                    if (command.contains("search")) {
                        System.out.println("Клиент: " + client + ", изменяет полёт.");
                        //Ждём номер полёта: int
                        int flightsNumber = sIn.readInt();
                        //Ждём тип аэробуса
                        String aircraft = (String) sIn.readObject();
                        //Ждём город прибытия
                        String arrTown = (String) sIn.readObject();
                        //Ждём аэропорт прибытия
                        String arrAirport = (String) sIn.readObject();
                        //Ждём город отправления
                        String depTown = (String) sIn.readObject();
                        //Ждём аэропорт отправления
                        String depAirport = (String) sIn.readObject();
                        //Ждём время отправления
                        Date depTime = (Date) sIn.readObject();
                       // Flights s = all.search(flightsNumber, aircraft, arrTown, arrAirport, depTown, depAirport, depTime);
                        //Обратно отправляем в ZIP-потоке новый список полётов
                        //GZIPOutputStream gsOut = new GZIPOutputStream(clientSocket.getOutputStream());
                        //sOut = new ObjectOutputStream(gsOut);
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
              //          sOut.writeObject(s);
                        sOut.flush();
                        bOut.flush();
                        //gsOut.flush();
                        //gsOut.finish();
                    }
                    //Обновление полета
                    if (command.contains("update")) {
                        System.out.println("Клиент: " + client + ", изменяет полёт.");
                        //Ждём полёт: Object -> Flight
                        Flight newFlight = (Flight) sIn.readObject();
                        all.updateFlight(newFlight);
                        //Обратно отправляем в ZIP-потоке новый список полётов
                        //GZIPOutputStream gsOut = new GZIPOutputStream(clientSocket.getOutputStream());
                        //sOut = new ObjectOutputStream(gsOut);
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        sOut.writeObject(all);
                        sOut.flush();
                        bOut.flush();
                        //gsOut.flush();
                        //gsOut.finish();
                    }
                    //Удаление
                    if (command.contains("delete")) {
                        System.out.println("Клиент: " + client + ", удаляет полёт.");
                        //Ждём номер полёта: int
                        int number = sIn.readInt();
                        System.out.println("Удаляем полёт с номером: " + number);
                        all.deleteFlightByFlightsNumber(number);
                        //Обратно отправляем в ZIP-потоке новый список полётов
                        //GZIPOutputStream gsOut = new GZIPOutputStream(clientSocket.getOutputStream());
                        //sOut = new ObjectOutputStream(gsOut);
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        sOut.writeObject(all);
                        sOut.flush();
                        bOut.flush();
                        //gsOut.flush();
                        //gsOut.finish();
                    }
                    //Добавление
                    if (command.contains("add")) {
                        System.out.println("Клиент: " + client + ", добавляет новый полёт.");
                        //Ждём полёт: Object -> Flight
                        Flight newFlight = (Flight) sIn.readObject();
                        newFlight.print();
                        all.addFlight(newFlight);
                        //Обратно отправляем в ZIP-потоке новый список полётов
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        sOut.writeObject(all);
                        sOut.flush();
                        bOut.flush();
                        //bOut.finish();
                    }
                    //Запрос ID
                    if (command.contains("ID")) {
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        //Отправляем ID: int
                        sOut.writeInt(id);
                        id++;
                    }
                    //Сохранение в файл
                    if (command.contains("Save")) {
                        //Ждём имя файла: Object -> String
                        filename = (String) sIn.readObject();
                        //Ждём флаг перезаписи: Boolean
                        boolean overwrite = sIn.readBoolean();
                        //Ждём данные: Object -> String
                        data = (String) sIn.readObject();
                        if (command.equals("SaveFlights")) {
                            ProcessXMLData.saveData(filename, ProcessXMLData.loadDataFromXML(data, Flights.class), overwrite);
                        }
                        if (command.equals("SaveRoutes")) {
                            ProcessXMLData.saveData(filename, ProcessXMLData.loadDataFromXML(data, Routes.class), overwrite);
                        }
                        if (command.equals("SavePoints")) {
                            ProcessXMLData.saveData(filename, ProcessXMLData.loadDataFromXML(data, Points.class), overwrite);
                        }
                    }
                    //Загрузка из файла
                    if (command.contains("Load")) {
                        //Ждём имя файла: Object -> String
                        filename = (String) sIn.readObject();
                        System.out.println("Имя файла: " + filename);
                        //Выходной поток ZIP
                        //GZIPOutputStream gsOut = new GZIPOutputStream(clientSocket.getOutputStream());
                        //sOut = new ObjectOutputStream(gsOut);
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        if (command.equals("LoadFlights")) {
                            sOut.writeObject(ProcessXMLData.saveDataToXML(ProcessXMLData.loadData(filename, Flights.class)));
                        }
                        if (command.equals("LoadRoutes")) {
                            sOut.writeObject(ProcessXMLData.saveDataToXML(ProcessXMLData.loadData(filename, Routes.class)));
                        }
                        if (command.equals("LoadPoints")) {
                            sOut.writeObject(ProcessXMLData.saveDataToXML(ProcessXMLData.loadData(filename, Points.class)));
                        }
                        sOut.flush();
                        //gsOut.flush();
                        //gsOut.finish();                        
                    }
                    //Перезагрузка данных
                    if (command.contains("reload")) {
                        System.out.println("Клиент: " +client + ", обновляет данные.");
                        //Ждём полёт: Object -> Flight
                        BufferedOutputStream bOut = new BufferedOutputStream(clientSocket.getOutputStream());
                        sOut = new ObjectOutputStream(bOut);
                        sOut.writeObject(all);
                        sOut.flush();
                        bOut.flush();
                    }
                    //Отключение клиента
                    if (command.contains("exit")) {
                        System.out.println("Клиент: "+client + ", отключился!");
                    }
                     if (command.contains("open")) {
                        System.out.println("Клиент: "+client + ", подключился!");
                    }
                } catch (ClassNotFoundException classnot) {
                    System.err.println("Data received in unknown format");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                allClients.remove(this);
                try {
                    if (sOut != null) {
                        sOut.close();
                    }
                    if (sIn != null) {
                        sIn.close();
                    }
                    clientSocket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }
        }

        @Override
        public void updateAddFlight(InterfaceObservable io, Flight newFlight) {
        }

        @Override
        public void updateDeleteFlight(InterfaceObservable io, Flight deleteFlight) {
        }

        @Override
        public void updateSearchComplete(InterfaceObservable io, Flights allSearchingFlights) {
        }

        @Override
        public void updateUpdateFlight(InterfaceObservable io, int index, Flight changedFlight) {
        }
    }
}
